﻿ #region Disclaimer/Info
 
 /////////////////////////////////////////////////////////////////////////////////////////////////
 //
 //   File:		RssService.cs
 //   Website:		http://dexterblogengine.com/
 //   Authors:		http://dexterblogengine.com/About.ashx
 //   Rev:		1
 //   Created:		19/01/2011
 //   Last edit:		19/01/2011
 //   License:		GNU Library General Public License (LGPL)
 // 
 //   For updated news and information please visit http://dexterblogengine.com/
 //   Dexter is hosted to Codeplex at http://dexterblogengine.codeplex.com
 //   For any question contact info@dexterblogengine.com
 //
 ///////////////////////////////////////////////////////////////////////////////////////////////////
 
 #endregion

using System;
using System.IO;
using System.Xml.Linq;
using Dexter.Core;
using Dexter.Logger.Contracts;
using Dexter.Web.Syndication.Contracts;
using Dexter.Web.Syndication.Model;
using Topics.Radical.Validation;

namespace Dexter.Web.Syndication.Concretes {
	public class RssService : IRssService , IRssServiceItem {
		readonly ILogger logger;
		XElement channel;
		XDocument doc;

		public RssService ( ILogger logger ) {
			this.logger = logger;
		}

		#region IRssService Members

		public IRssServiceItem CreateHeader ( RssHeader header ) {
			Ensure.That ( header )
				.Named ( "header" )
				.WithPreview ( ( v , e ) => logger.Warn ( v.GetFullErrorMessage ( ) , e ) )
				.IsNotNull ( )
				.WithMessage ( "Invalid rss header." );

			doc = new XDocument ( new XDeclaration ( "1.0" , "utf-8" , "yes" ) );

			var rss = new XElement ( "rss" , new XAttribute ( "version" , "2.0" ) );
			channel = new XElement ( "channel" );

			doc.Add ( rss );
			rss.Add ( channel );

			channel.Add ( new XElement ( "title" , header.Title ) );
			channel.Add ( new XElement ( "link" , header.Link ) );
			channel.Add ( new XElement ( "description" , header.Description ) );
			channel.Add ( new XElement ( "docs" , "http://www.rssboard.org/rss-specification" ) );
			channel.Add ( new XElement ( "generator" , DexterInfo.Generator ) );

			if ( header.Culture != null ) {
				channel.Add ( new XElement ( "language" , header.Culture ) );
			}

			if ( !string.IsNullOrEmpty ( header.EditorName ) ) {
				channel.Add ( new XElement ( "webMaster" , header.EditorName ) );
			}

			if ( header.PublishDate.HasValue ) {
				channel.Add ( new XElement ( "pubDate" , header.PublishDate.Value.ToRfc822 ( ) ) );
			}

			if ( header.LatestNewsDate.HasValue ) {
				channel.Add ( new XElement ( "lastBuildDate" , header.LatestNewsDate.Value.ToRfc822 ( ) ) );
			}

			if ( header.Categories != null && header.Categories.Length > 0 ) {
				foreach ( var category in header.Categories ) {
					channel.Add ( new XElement ( "category" , category ) );
				}
			}

			if ( header.EditorMailAddress != null ) {
				var editorMailAddress = string.Format ( "{0} ({1})" , header.EditorMailAddress.Address , header.EditorMailAddress.DisplayName );
				channel.Add ( new XElement ( "managingEditor" , editorMailAddress ) );
			}

			channel.Add ( new XElement ( "ttl" , "60" ) );

			return this;
		}

		#endregion

		#region IRssServiceItem Members

		public IRssServiceItem AddItem ( RssItem item ) {
			Ensure.That ( item )
				.Named ( "item" )
				.WithPreview ( ( v , e ) => logger.Warn ( v.GetFullErrorMessage ( ) , e ) )
				.IsNotNull ( )
				.WithMessage ( "Invalid rss item." );

			var itm = new XElement ( "item" );
			channel.Add ( itm );

			itm.Add ( new XElement ( "title", item.Title ) );
			itm.Add ( new XElement ( "description", item.Description ) );
			itm.Add ( new XElement ( "link", item.Link ) );
			itm.Add ( new XElement ( "author", item.Author ) );
			itm.Add ( new XElement ( "comments", item.CommentsLink ) );

			var guidElement = new XElement ( "guid" , new XAttribute ( "isPermaLink" , "true" ) );
			guidElement.SetValue ( item.Link );
			itm.Add ( guidElement );

			itm.Add ( new XElement ( "pubDate", item.PublishDate.ToRfc822 ( ) ) );

			foreach ( var category in item.Categories ) {
				itm.Add ( new XElement ( "category", category ) );
			}
			return this;
		}

		public IRssServiceItem AddItems ( RssItem[] item ) {
			foreach ( var rssItem in item ) {
				AddItem ( rssItem );
			}

			return this;
		}

		public XDocument ReturnFeed ( ) {
			return doc;
		}

		public void Save ( Stream stream ) {
			doc.Save ( stream );
		}

		#endregion
	}
}
